/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *   gbx-emu - common.h                                                    *
 *   gbx-emu homepage: http://code.google.com/p/gbx-emu/                   *
 *   Copyright (C) 2009 olejl77@gmail.com                                  *
 *                                                                         *
 *   This program is free software: you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation, either version 3 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the          *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef COMMON_H
#define COMMON_H
#pragma once
#include <cstdarg>
#include <iostream>
#include <QFile>
#include <QTextStream>

typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef char s8;
typedef short s16;
typedef int s32;
union reg {
    u16 w;
    struct {
        u8 l;
        u8 h;
    };
};

enum ROM_TYPES {
    ROM_ONLY                  = 0x00,
    ROM_MBC1                  = 0x01,
    ROM_MBC1_RAM              = 0x02,
    ROM_MBC1_RAM_BATT         = 0x03,
    ROM_MBC2                  = 0x05,
    ROM_MBC2_BATTERY          = 0x06,
    ROM_RAM                   = 0x08,
    ROM_RAM_BATTERY           = 0x09,
    ROM_MMM01                 = 0x0b,
    ROM_MMM01_SRAM            = 0x0c,
    ROM_MMM01_SRAM_BATT       = 0x0d,
    ROM_MBC3_TIMER_BATT       = 0x0f,
    ROM_MBC3_TIMER_RAM_BATT   = 0x10,
    ROM_MBC3                  = 0x11,
    ROM_MBC3_RAM              = 0x12,
    ROM_MBC3_RAM_BATT         = 0x13,
    ROM_MBC5                  = 0x19,
    ROM_MBC5_RAM              = 0x1a,
    ROM_MBC5_RAM_BATT         = 0x1b,
    ROM_MBC5_RUMBLE           = 0x1c,
    ROM_MBC5_RUMBLE_SRAM      = 0x1d,
    ROM_MBC5_RUMBLE_SRAM_BATT = 0x1e,
    Pocket_Camera             = 0x1f,
    Bandai_TAMA5              = 0xfd,
    Hudson_HuC_3              = 0xfe,
    Hudson_HuC_1              = 0xff
};

// NB! When editing these enums,
// make sure to add a line to log_names also.
enum LOG_TYPES {
    LOG_CART     = 1 << 0,
    LOG_CPU      = 1 << 1,
    LOG_DEBUGGER = 1 << 2,
    LOG_GAMEBOY  = 1 << 3,
    LOG_GUI      = 1 << 4,
    LOG_MAIN     = 1 << 5,
    LOG_MEMORY   = 1 << 6,
    LOG_SCREEN   = 1 << 7,

    ALL_LOGS     = 0xffff,
};

static const char *log_names[] = {
    "Cartridge",
    "Cpu",
    "Debugger",
    "Gameboy",
    "Gui",
    "Main",
    "Memory",
    "Screen",
};

enum LOG_LEVELS {
    ERROR_LEVEL   = 1 << 0,
    WARNING_LEVEL = 1 << 1,
    INFO_LEVEL    = 1 << 2,
    DEBUG_LEVEL   = 1 << 3,
    LOG_LEVEL     = 1 << 4,

    ALL_LEVELS    = 0xffff,
};

class Log
{
private:
    s32 m_logLevel;
    s32 m_logMask;
    QFile *m_file;
    QTextStream *m_log;

public:
    Log() {
        m_file = new QFile("./gbx-emu.log");
        if (!m_file->open(QIODevice::WriteOnly | QIODevice::Text))
            return;
        m_log = new QTextStream(m_file);
    }
    ~Log() {
        m_file->close();
        delete [] m_file;
        delete [] m_log;
        m_file = NULL;
        m_log = NULL;
    }
    void setLogLevel(s32 level) { m_logLevel = level; }
    void setLogMask(s32 mask)   { m_logMask = mask; }
    s32 getLogLevel()           { return m_logLevel; }
    s32 getLogMask()            { return m_logMask; }
    void enableType(s32 type)   { m_logMask |= type; }
    void disableType(s32 type)  { m_logMask &= ~type; }
    void enableLevel(s32 level) { m_logLevel |= level; }
    void disableLevel(s32 level){ m_logLevel &= ~level; }

    void Msg(LOG_LEVELS level, LOG_TYPES type, const char *format, ...) const
    {
        if ((level & m_logLevel) && (type & m_logMask)) {
            char tmp[256];

            va_list args;
            va_start(args, format);
#ifdef WIN32
			vsnprintf_s(tmp, 256, 256, format, args);
#else
			vsnprintf(tmp, 256, format, args);
#endif
            va_end(args);

            s32 pos, t;
            for (pos = 0, t = 1; t < ALL_LOGS; pos++, t<<=1) {
                if (t == type) {
                    break;
                }
            }

            switch (level) {
            case (ERROR_LEVEL):
                printf("%c[%d;%dm[%s] %s%c[%dm\n", 27, 0, 31, log_names[pos], tmp, 27, 0);
                break;
            case (WARNING_LEVEL):
                printf("%c[%d;%dm[%s] %s%c[%dm\n", 27, 0, 33, log_names[pos], tmp, 27, 0);
                break;
            case (INFO_LEVEL):
                printf("[%s] %s\n", log_names[pos], tmp);
                break;
            case (DEBUG_LEVEL):
                printf("%c[%d;%dm[%s] %s%c[%dm\n", 27, 0, 34, log_names[pos], tmp, 27, 0);
                break;
            case (LOG_LEVEL):
                *m_log << tmp << endl;
                break;
            default:
                break;
            }
        }
    }
};
class Common
{
protected:
    bool check_bit(u8 byte, u8 bit) const { return ((byte & (1 << bit)) > 0) ? true : false; }
    void set_bit(u8 *byte, u8 bit) { *byte |= (1 << bit); }
    void reset_bit(u8 *byte, u8 bit) { *byte &= ~(1 << bit); }
};

enum { dbgDisabled, dbgBreak, dbgStep, dbgTrace, dbgRun, dbgNext, dbgReset };

#endif // COMMON_H
